#ifndef clox_object_h
#define clox_object_h

#include "common.h"
#include "chunk.h"
#include "value.h"

#define OBJ_TYPE(value) (AS_OBJ(value)->type)
#define IS_FUNCTION(value) isObjType(value, OBJ_FUNCTION)
#define IS_NATIVE(value) isObjType(value, OBJ_NATIVE)
#define IS_STRING(value) isObjType(value, OBJ_STRING)
#define AS_FUNCTION(value) ((ObjFunction*)AS_OBJ(value))
// IS_NATIVE 如果返回值为真，下面这个宏可以从一个代表本地函数的Value中提取C函数指针
#define AS_NATIVE(value) \
(((ObjNative*)AS_OBJ(value)) -> function)
// 这两个宏会接受一个Value，其中应当包含一个指向堆上的有效ObjString指针。第一个函数返回 ObjString* 指针。
#define AS_STRING(value) ((ObjString*)AS_OBJ(value))
//第二个函数更进一步返回了字符数组本身，因为这往往是我们最终需要的。
#define AS_CSTRING(value) (((ObjString*)AS_OBJ(value))->chars)
typedef enum {
    OBJ_FUNCTION,
    OBJ_NATIVE,
    OBJ_STRING,
} ObjType;
struct Obj {
    ObjType type;
    struct Obj* next;
};
typedef struct {
    // 函数是Lox中的一等公民，所以它们需要作为实际的Lox对象。因此，ObjFunction具有所有对象类型共享的Obj头。
    Obj obj;
    // arity字段存储了函数所需要的参数数量。
    int arity;
    Chunk chunk;
    // 函数名称
    ObjString* name;
} ObjFunction;
typedef Value (*NativeFn)(int argCount, Value* args);

typedef struct {
    Obj obj;
    NativeFn function;
} ObjNative;
struct ObjString {
    Obj obj;
    int length;
    char* chars;
    uint32_t hash;
};
// 我们定义一些辅助程序，使Lox函数更容易在C语言中使用。有点像穷人版的面向对象。
ObjFunction* newFunction();
ObjNative* newNative(NativeFn function);

ObjString* takeString(char* chars, int length);
ObjString* copyString(const char* chars, int length);
void printObject(Value value);
static inline bool isObjType(Value value, ObjType type) {
    return IS_OBJ(value) && AS_OBJ(value)->type == type;
}
#endif